package data

import (
	"sync"
	"time"
)

type TsValue struct {
	T int64  // 毫秒时间戳  // timestamp
	V string // value 采集值
}

type Point struct {
	id string // 冗余字段
	t  int64  // 毫秒时间戳
	v  string // value 采集值
}

func NewPoint(id string, t int64, v string) *Point {
	return &Point{id, t, v}
}

type SafeQueue struct {
	mu     sync.Mutex
	ptId   string
	expire int // 过期时间秒 2分钟就是 120
	items  []*Point
}

func NewQueue(ptid string) *SafeQueue {
	tmp := &SafeQueue{
		ptId:   ptid,
		expire: 60 * 3,
		items:  make([]*Point, 0, 200),
	}
	return tmp
}

func (q *SafeQueue) GetPtId() string {
	return q.ptId
}

// recovery 过期数据
func (q *SafeQueue) unsafeRecovery() {
	// 校验时间 删除过期数据
	_expire := time.Now().UnixMilli() - int64(q.expire*1000)
	var n int = 0
	for i := 0; i < len(q.items); i++ {
		if q.items[i].t < _expire {
			n++
		} else {
			break
		}
	}
	if n > 0 {
		q.items = q.items[n:]
	}
}

// 新增数据
func (q *SafeQueue) Enqueue(item *Point) {
	q.mu.Lock()
	defer q.mu.Unlock()

	// 校验时间 删除过期数据
	q.unsafeRecovery()
	//
	q.items = append(q.items, item)
}

// 深度拷贝数组
func (q *SafeQueue) DeepArray() []*Point {
	q.mu.Lock()
	defer q.mu.Unlock()

	if len(q.items) == 0 {
		return make([]*Point, 0)
	}

	// 校验时间 删除过期数据
	q.unsafeRecovery()

	newItems := make([]*Point, 0, len(q.items))
	for _, tmp := range q.items {
		item := new(Point)
		item.id = q.ptId
		item.t = tmp.t
		item.v = tmp.v
		newItems = append(newItems, item)
	}
	return newItems
}

// 最近的数据 在某个时间点后的数据  afterms是毫秒, 云端配置的时间*1000
func (q *SafeQueue) RecentValues(afterms int64) []*TsValue {
	q.mu.Lock()
	defer q.mu.Unlock()

	rst := make([]*TsValue, 0, len(q.items))
	for _, tmp := range q.items {
		if tmp.t > afterms {
			item := new(TsValue)
			item.T = tmp.t
			item.V = tmp.v
			rst = append(rst, item)
		}
	}
	// 网关默认都是顺序的 应该就不需要排序了
	return rst
}

func (q *SafeQueue) Len() int {
	q.mu.Lock()
	defer q.mu.Unlock()
	return len(q.items)
}

// Dequeue Dequeue 不用这个
func (q *SafeQueue) Dequeue() *Point {
	q.mu.Lock()
	defer q.mu.Unlock()

	if len(q.items) == 0 {
		return nil
	}

	tmp := q.items[0]
	q.items = q.items[1:]

	// *point
	item := new(Point)
	item.id = q.ptId
	item.t = tmp.t
	item.v = tmp.v
	// 内存释放
	tmp = nil
	return item
}
